package carassius.DAL;

import carassius.BLL.Events.Organism.OrganismPropertyChangedEvent;
import carassius.BLL.Events.Organism.OrganismPropertyChangedEvent.OrganismProperty;
import carassius.BLL.Events.Organism.OrganismPropertyChangedEventListener;
import carassius.BLL.Events.Organism.OrganismPropertyChangedEventPublisher;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;

/**
 *
 * @author siebz0r
 */
public abstract class OrganismRow
		extends Row<Integer>
		implements OrganismPropertyChangedEventPublisher,
				   Comparable<OrganismRow>
{
	//<editor-fold defaultstate="collapsed" desc="Fields">
	private final int ID;
	private Integer _minTemperature, _maxtemperature;//, _difficulty;
	private String _scientificName, _alternativeName, _description;
	private Double _maxSize;
	private PictureRow _picture;
	private final Object MIN_TEMPERATURE_LOCK,
			MAX_TEMPERATURE_LOCK,
			SCIENTIFIC_NAME_LOCK,
			ALTERNATIVE_NAME_LOCK,
			DESCRIPTION_LOCK,
			MAX_SIZE_LOCK,
			PICTURE_LOCK;
	private final ArrayList<OrganismPropertyChangedEventListener> _organismPropertyChangedEventListeners;
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Constructors">
	public OrganismRow(ResultSet resultSet) throws SQLException
	{
		super(resultSet.getInt("id"));
		ID = resultSet.getInt("id");
		_minTemperature = resultSet.getInt("min_temperature");
		_maxtemperature = resultSet.getInt("max_temperature");
		_scientificName = resultSet.getString("scientific_name");
		_alternativeName = resultSet.getString("alternative_name");
		_description = resultSet.getString("description");
		_maxSize = resultSet.getDouble("max_size");
		_picture = Database.getPictureTable().getByPrimaryKey(resultSet.getInt("picture_id"));
		_organismPropertyChangedEventListeners = new ArrayList<OrganismPropertyChangedEventListener>();
		MIN_TEMPERATURE_LOCK = new Object();
		MAX_TEMPERATURE_LOCK = new Object();
		SCIENTIFIC_NAME_LOCK = new Object();
		ALTERNATIVE_NAME_LOCK = new Object();
		DESCRIPTION_LOCK = new Object();
		MAX_SIZE_LOCK = new Object();
		PICTURE_LOCK = new Object();
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Public Properties">
	public int getId()
	{
		return ID;
	}

	public String getAlternativeName()
	{
		synchronized (ALTERNATIVE_NAME_LOCK)
		{
			return _alternativeName;
		}
	}

	public boolean setAlternativeName(String alternativeName)
	{
		boolean result = false;
		synchronized (ALTERNATIVE_NAME_LOCK)
		{
			if (_alternativeName == null ? alternativeName != null : !_alternativeName.equals(alternativeName))
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE organism SET alternative_name = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						if (alternativeName != null)
						{
							st.setString(1, alternativeName);
						}
						else
						{
							st.setNull(1, java.sql.Types.VARCHAR);
						}
						st.setInt(2, ID);

						if (st.executeUpdate() == 1)
						{
							fireOrganismPropertyChangedEvent(OrganismProperty.AlternativeName, _alternativeName, alternativeName);
							_alternativeName = alternativeName;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_alternativeName = alternativeName;
				}
			}
		}
		return result;
	}

	public String getDescription()
	{
		synchronized (DESCRIPTION_LOCK)
		{
			return _description;
		}
	}

	public boolean setDescription(String description)
	{
		boolean result = false;
		synchronized (DESCRIPTION_LOCK)
		{
			if (_description == null ? description != null : !_description.equals(description))
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE organism SET description = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						if (description != null)
						{
							st.setString(1, description);
						}
						else
						{
							st.setNull(1, java.sql.Types.VARCHAR);
						}
						st.setInt(2, ID);

						if (st.executeUpdate() == 1)
						{
							fireOrganismPropertyChangedEvent(OrganismProperty.Description, _description, description);
							_description = description;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_description = description;
				}
			}
		}
		return result;
	}

	public Double getMaxSize()
	{
		synchronized (MAX_SIZE_LOCK)
		{
			return _maxSize;
		}
	}

	public boolean setMaxSize(Double maxSize)
	{
		boolean result = false;
		synchronized (MAX_SIZE_LOCK)
		{
			if (maxSize != _maxSize)
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE organism SET max_size = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						st.setObject(1, maxSize, Types.DOUBLE);
						st.setInt(2, ID);

						if (st.executeUpdate() == 1)
						{
							fireOrganismPropertyChangedEvent(OrganismProperty.MaxSize, _maxSize, maxSize);
							_maxSize = maxSize;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_maxSize = maxSize;
				}
			}
		}
		return result;
	}

	public Integer getMaxtemperature()
	{
		synchronized (MAX_TEMPERATURE_LOCK)
		{
			return _maxtemperature;
		}
	}

	public boolean setMaxtemperature(Integer maxtemperature)
	{
		boolean result = false;
		synchronized (MAX_TEMPERATURE_LOCK)
		{
			if (maxtemperature != _maxtemperature)
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE organism SET max_temperature = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						st.setObject(1, maxtemperature, Types.INTEGER);
						st.setInt(2, ID);

						if (st.executeUpdate() == 1)
						{
							fireOrganismPropertyChangedEvent(OrganismProperty.Maxtemperature, _maxtemperature, maxtemperature);
							_maxtemperature = maxtemperature;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_maxtemperature = maxtemperature;
				}
			}
		}
		return result;
	}

	public Integer getMinTemperature()
	{
		synchronized (MIN_TEMPERATURE_LOCK)
		{
			return _minTemperature;
		}
	}

	public boolean setMinTemperature(Integer minTemperature)
	{
		boolean result = false;
		synchronized (MIN_TEMPERATURE_LOCK)
		{
			if (minTemperature != _minTemperature)
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE organism SET min_temperature = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						st.setObject(1, minTemperature, Types.INTEGER);
						st.setInt(2, ID);

						if (st.executeUpdate() == 1)
						{
							fireOrganismPropertyChangedEvent(OrganismProperty.MinTemperature, _minTemperature, minTemperature);
							_minTemperature = minTemperature;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_minTemperature = minTemperature;
				}
			}
		}
		return result;
	}

	public PictureRow getPicture()
	{
		synchronized (PICTURE_LOCK)
		{
			return _picture;
		}
	}

	public boolean setPicture(PictureRow picture)
	{
		boolean result = false;
		synchronized (PICTURE_LOCK)
		{
			if ((_picture == null) ? (picture != null) : !_picture.equals(picture))
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE organism SET picture_id = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						st.setObject(1, (picture != null) ? picture.getId() : null, java.sql.Types.INTEGER);
						st.setInt(2, ID);

						if (st.executeUpdate() == 1)
						{
							fireOrganismPropertyChangedEvent(OrganismProperty.Picture, _picture, picture);
							_picture = picture;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_picture = picture;
				}
			}
		}
		return result;
	}

	public String getScientificName()
	{
		synchronized (SCIENTIFIC_NAME_LOCK)
		{
			return _scientificName;
		}
	}

	public boolean setScientificName(String scientificName)
	{
		boolean result = false;
		synchronized (SCIENTIFIC_NAME_LOCK)
		{
			if (scientificName == null ? _scientificName != null : !scientificName.equals(_scientificName))
			{
				if (getId() >= 0)
				{
					try
					{
						String sql = "UPDATE organism SET scientific_name = ? where id = ?";
						PreparedStatement st = Database.prepareStatement(sql);
						if (scientificName != null)
						{
							st.setString(1, scientificName);
						}
						else
						{
							st.setNull(1, java.sql.Types.VARCHAR);
						}
						st.setInt(2, ID);

						if (st.executeUpdate() == 1)
						{
							fireOrganismPropertyChangedEvent(OrganismProperty.ScientificName, _scientificName, scientificName);
							_scientificName = scientificName;
							result = true;
						}
					}
					catch (SQLException ex)
					{
						System.out.println(ex.toString());
					}
				}
				else
				{
					_scientificName = scientificName;
				}
			}
		}
		return result;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Public Methods">
	@Override
	public boolean equals(Object obj)
	{
		if (obj == null)
		{
			return false;
		}
		if (getClass() != obj.getClass())
		{
			return false;
		}
		final OrganismRow other = (OrganismRow) obj;
		if (this.ID != other.ID)
		{
			return false;
		}
		if (this._minTemperature != other._minTemperature)
		{
			return false;
		}
		if (this._maxtemperature != other._maxtemperature)
		{
			return false;
		}
		if ((this._scientificName == null) ? (other._scientificName != null) : !this._scientificName.equals(other._scientificName))
		{
			return false;
		}
		if ((this._alternativeName == null) ? (other._alternativeName != null) : !this._alternativeName.equals(other._alternativeName))
		{
			return false;
		}
		if ((this._description == null) ? (other._description != null) : !this._description.equals(other._description))
		{
			return false;
		}
		if (Double.doubleToLongBits(this._maxSize) != Double.doubleToLongBits(other._maxSize))
		{
			return false;
		}
		if (this._picture != other._picture && (this._picture == null || !this._picture.equals(other._picture)))
		{
			return false;
		}
		return true;
	}

	@Override
	public int hashCode()
	{
		int hash = 7;
		return hash;
	}

	@Override
	public int compareTo(OrganismRow o)
	{
		return toString().compareTo(o.toString());
	}

	@Override
	public String toString()
	{
		if (_scientificName != null && _scientificName.length() > 0)
		{
			return _scientificName;
		}
		else
		{
			return _alternativeName;
		}
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Events">
	//<editor-fold defaultstate="collapsed" desc="Organism Property Changed">
	@Override
	public void addOrganismPropertyChangedEventListener(
			OrganismPropertyChangedEventListener listener)
	{
		synchronized (_organismPropertyChangedEventListeners)
		{
			_organismPropertyChangedEventListeners.add(listener);
		}
	}

	@Override
	public void removeOrganismPropertyChangedEventListener(
			OrganismPropertyChangedEventListener listener)
	{
		synchronized (_organismPropertyChangedEventListeners)
		{
			_organismPropertyChangedEventListeners.remove(listener);
		}
	}

	private void fireOrganismPropertyChangedEvent(OrganismProperty property,
												  Object oldVal, Object newVal)
	{
		final OrganismPropertyChangedEvent evt = new OrganismPropertyChangedEvent(this, property, oldVal, newVal);
		synchronized (_organismPropertyChangedEventListeners)
		{
			for (OrganismPropertyChangedEventListener listener : _organismPropertyChangedEventListeners)
			{
				listener.organismPropertyChanged(evt);
			}
		}
	}
	//</editor-fold>
	//</editor-fold>
}
